import * as PIXI from "pixi.js";
import Vec2 from "vec2";
import EventEmitter from "eventemitter3";
import ControlBtn from "./ControlBtn";
import Dashline from "./Dashline";
import DelBtn from "./DelBtn";
import { makeObjectDraggable } from "../utils";

class EditableObject extends EventEmitter {
  editableObject = null;

  dashLine;

  delBtn;

  controlBtn;

  originDataMap = {};

  defaultAngle;

  defaultDistance;

  initObjEvent() {
    this.obj.interactive = false;
    return this.editableObject;
  }

  getAllControlSprite = () => {
    const getSprite = this.editableObject?.getChildByName.bind(
      this.editableObject
    );
    const delBtn = getSprite?.("delBtn");
    const ctrlBtn = getSprite?.("ctrlBtn");
    const dashline = getSprite?.("dashline");

    return {
      delBtn,
      ctrlBtn,
      dashline,
    };
  };

  makeObjectUnEditable() {
    const { delBtn, ctrlBtn, dashline } = this.getAllControlSprite();

    delBtn.visible = false;
    ctrlBtn.visible = false;
    dashline.visible = false;
  }

  recoverEditable = () => {
    const { delBtn, ctrlBtn, dashline } = this.getAllControlSprite();

    delBtn.visible = true;
    ctrlBtn.visible = true;
    dashline.visible = true;
  };

  makeSpriteEditable = () => {
    setTimeout(() => {
      this.emit("Selected", this);
    }, 100);

    if (this.editableObject) {
      this.recoverEditable();
      return;
    }

    // todo？初始化和 选择的时候

    // 先拿到之前的位置
    const obj = this.obj;
    const originX = obj.x;
    const originY = obj.y;
    const originPX = obj.pivot.x;
    const originPY = obj.pivot.y;

    // 归零数值开始渲染，防止后续container位置偏移
    // 中心点是人物obj的中心，如果设置为0，那么就变成左上角中间了
    // 因为 obj 被添加到 新的 container 了，所以设置相对于contianer，而 contianer 则拿了 obj的位置
    obj.x = 0;
    obj.y = 0;
    obj.pivot.x = 0;
    obj.pivot.y = 0;

    // 编辑态有虚线框、两个按钮
    this.dashLine = new Dashline(obj).create();
    this.delBtn = new DelBtn(this.app, obj).create();
    this.controlBtn = new ControlBtn(this.app, obj).create();

    // 初始化工具事件
    this.initControlEvent();

    // 创建一个新的容器
    const container = new PIXI.Container();
    container.addChild(this.dashLine, this.obj, this.delBtn, this.controlBtn);

    // 恢复容器至原始素材位置
    container.x = originX;
    container.y = originY;
    container.pivot.x = originPX;
    container.pivot.y = originPY;

    // 让新容器可以拖拽
    makeObjectDraggable(container);

    this.editableObject = container;

    this.editableObject.on("pointerup", this.makeSpriteEditable);

    this.app.stage.addChild(container);

    this.saveObjectOriginData();
  };

  saveObjectOriginData = () => {
    const originDataMap = this.originDataMap;
    const ctrlBtn = this.controlBtn;
    const delBtn = this.delBtn;
    const dashLine = this.dashLine;
    const editableObject = this.editableObject;

    // 存下编辑实例的基础数据
    originDataMap.editableObject = {
      width: editableObject.width,
      height: editableObject.height,
      x: editableObject?.x,
      y: editableObject?.y,
    };
    originDataMap.dash = {
      x: dashLine?.x,
      y: dashLine?.y,
      width: dashLine?.width,
      height: dashLine?.height,
    };
    originDataMap.deleteIconSprite = {
      x: delBtn?.x,
      y: delBtn?.y,
      width: delBtn?.width,
      height: delBtn?.height,
    };
    originDataMap.controlIconSprite = {
      x: ctrlBtn?.x,
      y: ctrlBtn?.y,
      width: ctrlBtn?.width,
      height: ctrlBtn?.height,
    };
  };

  initEvents() {
    this.initDeleteIconEvent();
    this.initControlIconEvent();
  }

  initDeleteIconEvent() {
    if (this.delBtn) {
      // 使删除按钮可交互
      this.delBtn.interactive = true;
      this.delBtn.on("pointerdown", () => {
        this.emit("Delete", this);
        this.editableObject = null;
      });
    }
  }

  initControlIconEvent() {
    if (this.controlBtn) {
      // 使操作按钮可交互
      this.controlBtn.interactive = true;

      // 光标选中事件
      this.controlBtn.on("pointerdown", this.onCtrlDown);

      // 光标脱离事件
      this.controlBtn.on("pointerup", this.onCtrlUp);

      // 光标拖出事件
      this.controlBtn.on("pointerupoutside", this.onCtrlOut);

      // 光标拖动事件
      this.controlBtn.on("pointermove", this.onCtrlMove);
    }
  }

  onCtrlUp = () => {
    dragging = false;
    if (this.editableObject) {
      this.editableObject.interactive = true;
    }
  };

  onCtrlOut = () => {
    dragging = false;
    if (this.editableObject) {
      this.editableObject.interactive = true;
    }
  };

  onCtrlDown = (e) => {
    dragging = true;
    const editableObject = this.editableObject;

    // 如果保存了初始值，就不需要保存了
    if (!this.defaultDistance) {
      const { distance, angle } = this.getChangeDataFromObj(e);
      this.defaultDistance = distance;
      this.defaultAngle = angle;
    }

    if (editableObject) {
      editableObject.interactive = false;
    }
  };

  onCtrlMove = (e) => {
    const editableObject = this.editableObject;
    if (dragging) {
      const { distance, angle } = this.getChangeDataFromObj(e);

      // 把当前的距离 除以 最开始的具体，得到缩放了多少
      const vScale = distance / this.defaultDistance;

      const vAngle = angle - this.defaultAngle;

      const originMap = this.originDataMap;
      const delBtn = this.delBtn;
      const controlBtn = this.controlBtn;

      const delData = originMap.deleteIconSprite;
      const ctrlData = originMap.controlIconSprite;
      const editObjData = originMap.editableObject;

      if (delBtn) {
        delBtn.width = delData.width / vScale;
        delBtn.height = delData.height / vScale;
      }

      if (controlBtn) {
        controlBtn.width = ctrlData.width / vScale;
        controlBtn.height = ctrlData.height / vScale;
      }

      // 等比缩放基础元素
      editableObject.width = vScale * editObjData.width;
      editableObject.height = vScale * editObjData.height;
      editableObject.rotation = vAngle;
    }
  };

  getChangeDataFromObj = (e) => {
    const editableObject = this.editableObject;
    const globalData = e.data.global;
    const a = new Vec2(editableObject?.x || 0, editableObject?.y || 0);
    const b = new Vec2(globalData.x, globalData.y);
    return {
      distance: a.distance(b),
      angle: Math.atan2(
        globalData.y - (editableObject?.y || 0),
        globalData.x - (editableObject?.x || 0)
      ),
    };
  };
}
